package cn.hxsteel.storage.core.filter;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang.StringUtils;

import cn.hxsteel.purview.core.config.constant.RoleConst;
import cn.hxsteel.purview.core.exception.PermitFailException;
import cn.hxsteel.purview.core.tool.PurviewTool;
import cn.hxsteel.purview.core.tool.SessionTool;
import cn.hxsteel.purview.model.vo.SessionVO;
import cn.hxsteel.storage.core.config.constant.CommonConst;
import cn.hxsteel.storage.model.po.CustomerPO;

/**
 * web资源地址请求过滤器
 */
// @formatter:off
public class WebURIFilter implements Filter
{
    /**
     * 已经被过滤过的请求的过滤属性键
     */
    private static final String   FILTERED_REQUEST_ATTRIBUTE_KEY = "@@session_context_filtered_request";
    
    /**
     * 不需要登录即可访问的相对资源地址的前缀
     */
    // @formatter:off
    private static final String[] LOGIN_CHECK_ESCAPE_URI_PREFIX  = { 
	"/favicon.ico",
	"/resource",
	"/valid",
	"/out",
	"/register",
	"/login",
	"/upload"
    };
    
    /**
     * 不需要验证权限的相对资源地址
     */
    // @formatter:off
    private static final String[] PERMIT_ESCAPE_URI              = {
	"/",
	"/index",
	"/logout",
	"/page/nav/side",
	"/page/nav/top",
	"/page/nav/do"
	};
    
    public void doFilter( ServletRequest request, ServletResponse response, FilterChain chain )
	    throws IOException, ServletException
    {
	// ①-1 保证该过滤器在一次请求中只被调用一次
	if ( request != null && request.getAttribute( FILTERED_REQUEST_ATTRIBUTE_KEY ) != null )
	{
	    chain.doFilter( request, response );
	}
	else
	{
	    // ①-2 设置过滤标识，防止一次请求多次过滤
	    request.setAttribute( FILTERED_REQUEST_ATTRIBUTE_KEY, true );
	    
	    HttpServletRequest httpRequest = (HttpServletRequest) request;
	    SessionVO< ? > sessionVO = SessionTool.getSessionVO( httpRequest );
	    
	    // ①-3 用户未登录, 且资源地址需要登录才能访问
	    if ( sessionVO == null && isNeedLoginURI( httpRequest ) )
	    {
		String toURI = httpRequest.getRequestURL().toString();
		if ( !StringUtils.isEmpty( httpRequest.getQueryString() ) )
		{
		    toURI += "?" + httpRequest.getQueryString();
		}
		
		// ①-4 将用户的请求资源地址保存在Session中，用于登录成功之后，跳到目标资源地址
		httpRequest.getSession().setAttribute( CommonConst.SESSION_LOGIN_TO_URI, toURI );
		
		// ①-5 转发到登录页面
		request.getRequestDispatcher( "/view/jsp/user/login.jsp" ).forward( request, response );
		return;
	    }
	    
	    // ①-6 拦截未分配权限的资源地址
	    if ( isNeedLoginURI( httpRequest ) && !isPermitURI( httpRequest ) )
	    {
		request.setAttribute( "exception", new PermitFailException() );
		request.getRequestDispatcher( "/view/jsp/fail.jsp" ).forward( request, response );
		return;
	    }
	    chain.doFilter( request, response );
	}
    }
    
    public void init( FilterConfig filterConfig )
	    throws ServletException
    {   
	
    }
    
    public void destroy()
    {   
	
    }
   
    /**
     * 相对的资源地址是否需要登录才能访问
     * 
     * @return
     */
    private boolean isNeedLoginURI( HttpServletRequest request )
    {
	String uri = request.getRequestURI();
	for ( String string : LOGIN_CHECK_ESCAPE_URI_PREFIX )
	{
	    if ( uri != null && uri.indexOf( string ) >= 0 ) { return false; }
	}
	return true;
    }
    
    /**
     * 相对的资源地址是否已经被分配访问权限
     * 
     * @return
     */
    private boolean isPermitURI( HttpServletRequest request )
    {
	String currentURI = request.getRequestURI();
	for ( String string : PERMIT_ESCAPE_URI )
	{
	    if (currentURI.equals( string ))
	    {
		return true;
	    }
	}
	SessionVO<CustomerPO> sessionVO = SessionTool.getSessionVO( CustomerPO.class, request );
	if (sessionVO != null)
	{
    	    if ( sessionVO.getRoleIDSet().contains( RoleConst.SYSTEM_SIGN ) )
    	    {
    	        return true;
    	    }
    	    String actionID = PurviewTool.getActionID( currentURI );
    	    if (sessionVO.getActionIDSet().contains( actionID ))
    	    {
    	        return true;
    	    }
	}
	return false;
    }
}